<template>
    <v-fade-transition hide-on-leave>
        <!-- 没有选中任何 Midi 时 -->
        <div v-if="selected.size === 0" class="mt-2 function-header">
            <!-- 打开文件 -->
            <v-btn class="ms-4" @click="addMidiItems(false)" color="primary">
                <template v-slot:prepend>
                    <v-icon color="background">mdi-file-plus-outline</v-icon>
                </template>
                打开文件
            </v-btn>

            <!-- 打开目录 -->
            <v-btn class="ms-4" @click="addMidiItems(true)" color="primary">
                <template v-slot:prepend>
                    <v-icon color="background">mdi-folder-plus-outline</v-icon>
                </template>
                打开目录
            </v-btn>
        </div>

        <!-- 选中了 Midi 时 -->
        <v-sheet v-else class="mx-3 mb-6 rounded-lg function-header-select" :elevation="4">
            <!-- 全不选 或 全选 -->
            <span style="width: 40px">
                <v-checkbox-btn
                    :model-value="selected.size === playlist.items.length"
                    @update:model-value="selectNoneOrAll"
                />
            </span>

            <!-- 已选择的 Midi 数量 -->
            <span class="expanded-content">已选择 {{ selected.size }} 个项目</span>

            <!-- 添加到... -->
            <v-btn class="me-4" @click="dialogState = true" color="primary">
                <template v-slot:prepend>
                    <v-icon color="background">mdi-star-outline</v-icon>
                </template>
                添加到...
            </v-btn>

            <!-- 删除 -->
            <v-btn class="me-4" @click="deleteSelected" color="error">
                <template v-slot:prepend>
                    <v-icon color="background">mdi-trash-can-outline</v-icon>
                </template>
                删除
            </v-btn>
        </v-sheet>
    </v-fade-transition>

    <!-- 播放列表 -->
    <div class="scrollbar">
        <playlist-items
            :playlist="playlist"
            :selected="selected"
            @toggle-play="(index) => emits('togglePlay', index)"
            @move-up="(index) => emits('moveUp', index)"
            @move-down="(index) => emits('moveDown', index)"
            @remove="(index) => emits('delete', index)"
        />
    </div>

    <confirm-dialog
        v-model="dialogState"
        title="添加到"
        @confirm="addMidiItemToStarlist(starlistName)"
        @cancel="dialogState = false"
    >
        <v-combobox :items="star.all" v-model="starlistName" label="收藏列表（不填添加到播放列表）" />
    </confirm-dialog>
</template>

<script setup lang="ts">
import { PropType, ref } from "vue";
import { Midi, MidiItem } from "@/lib/midi";
import { selectMidiFiles } from "@/lib/utils";
import { injectMessageState } from "@/lib/view";
import { Playlist, PlaylistObject } from "@/lib/playlist";
import useStarStore from "@/store/star";
import usePlaylistStore from "@/store/playlist";
import PlaylistItems from "@/components/playlist/PlaylistItems.vue";

const star = useStarStore();
const sPlaylist = usePlaylistStore();

const dialogState = ref(false);
const starlistName = ref<string | null | undefined>(undefined);

const messageState = injectMessageState();

const props = defineProps({
    playlist: {
        type: Object as PropType<PlaylistObject>,
        default: () => Playlist.object(),
    },
    selected: {
        type: Object as PropType<Set<number>>,
        default: () => new Set<number>(),
    },
});

const emits = defineEmits<{
    (event: "togglePlay", index: number): void;
    (event: "moveUp", index: number): void;
    (event: "moveDown", index: number): void;
    (event: "add", ...urls: MidiItem[]): void;
    (event: "delete", ...index: number[]): void;
    (event: "updateStar", name: string, items: MidiItem[]): void;
}>();

/**
 * 添加 MidiItem
 * @param openDir 是否打开目录
 */
async function addMidiItems(openDir: boolean) {
    // 弹出窗口，选中 Midi 文件
    const urls = await selectMidiFiles(openDir);

    if (urls.length === 0) {
        return;
    }

    // Midi 项列表
    const midiItems: MidiItem[] = [];

    // 读取 Midi 项
    const tasks = urls.map(async (url) => {
        const midi = await Midi.fromUrl(url);
        if (midi !== undefined) {
            midiItems.push(midi);
        }
    });

    // 等待读取完成
    await Promise.all(tasks);

    // 发送事件
    midiItems.sort((a, b) => a.name.localeCompare(b.name));
    emits("add", ...midiItems);
}

/**
 * 全选 或 全不选
 * @param all 是否全选
 */
function selectNoneOrAll(all: boolean) {
    if (all) {
        for (let i = 0; i < props.playlist.items.length; i++) {
            props.selected.add(i);
        }
    } else {
        props.selected.clear();
    }
}

/**
 * 添加到某个收藏列表
 * @param name 收藏列表名
 */
async function addMidiItemToStarlist(name: string | null | undefined) {
    // 获取选中的 Midi 项
    const items = Array.from(props.selected)
        .sort()
        .map((index) => props.playlist.items[props.playlist.indexes[index]]);

    // 加载列表
    if (name === null || name === undefined || name === "") {
        // 新增到播放列表
        try {
            sPlaylist.insert(...items);
        } catch (error) {
            console.warn("添加到播放列表失败");
            messageState.visible = true;
            messageState.text = `添加到播放列表失败`;
            return;
        }
    } else {
        // 新增 或 追加 到收藏列表
        try {
            let starlist = await star.load(name);

            if (starlist === undefined) {
                starlist = Playlist.object();
            }

            // 添加到收藏列表
            starlist.items.push(...items);
            await star.save(name || "播放列表", starlist);
        } catch (error) {
            console.warn("添加到收藏列表", name, "失败", error);
            messageState.visible = true;
            messageState.text = `添加到收藏列表 “${name}” 失败`;
            return;
        }
    }

    // 清除选中状态，关闭对话框
    props.selected.clear();
    dialogState.value = false;

    // 发送事件
    emits("updateStar", name ?? "", items);
}

/**
 * 删除选中的 Midi
 */
function deleteSelected() {
    if (props.selected.size > 0) {
        emits("delete", ...Array.from(props.selected));
        props.selected.clear();
    } else {
        messageState.visible = true;
        messageState.text = "请选择要删除的项目";
    }
}
</script>

<style scoped lang="scss">
.function-header {
    height: 64px;
    width: 100%;
    display: flex;
    flex-direction: row;
}

.function-header-select {
    height: 48px;
    display: flex;
    flex-direction: row;
    align-items: center;
    user-select: none;
}

.scrollbar {
    height: 0;
    flex-grow: 1;
    width: 100%;
}

.expanded-content {
    width: 0;
    flex-grow: 1;
}
</style>
